package org.wechat4j.utils;

import org.wechat4j.config.ApiConfig;

import javax.net.ssl.*;
import java.io.*;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @author bjliuyong
 * @version 1.0
 * @created date 16-11-8
 */
public class Https {

    public static String HTTP_GET = "GET" ;
    public static String HTTP_POST = "POST" ;

    public static String HTTPS_PROTOCAL = "https";

    private static SSLSocketFactory sslSocketFactory ;

    static {
        try {

            System.setProperty("https.protocols", "TLSv1");

            TrustManager[] trustManager = {new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            }};
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, trustManager, new java.security.SecureRandom());
            sslSocketFactory = sslContext.getSocketFactory();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static AtomicLong boundaryLongVal = new AtomicLong(System.currentTimeMillis());

    /**
     *
     * Http upload format
     *
     * Content-Type:multipart/form-data; boundary=----WebKitFormBoundarybNdkZO1wKWGkNgUL
     *
     * ------WebKitFormBoundarybNdkZO1wKWGkNgUL
     * Content-Disposition: form-data; name="media"; filename="VID_20150715_160019.mp4"
     * Content-Type: video/mp4
     *
     * ------WebKitFormBoundarybNdkZO1wKWGkNgUL--
     *
     * @param requestUrl
     * @param filePath
     * @return
     */
    public static String uploadFile(String requestUrl , String filePath ,String formId) {

        HttpURLConnection httpURLConnection = null ;
        InputStream inputStream  = null ;
        OutputStream outputStream = null ;
        try {

            File file = new File(filePath);

            httpURLConnection = openConnection(requestUrl);
            httpURLConnection.setRequestMethod(HTTP_POST);


            String BOUNDARY = "----" + boundaryLongVal.getAndIncrement() ;
            String contentType = "multipart/form-data; boundary=" + BOUNDARY ;
            httpURLConnection.setRequestProperty("Content-Type",contentType);

            //正文内容必须比请求头里面的边界多两个--
            //换行符 使用\r\n\
            //requestPayLoad  header
            String header = "--" + BOUNDARY  + "\r\n"  +
                            "Content-Disposition: form-data;name=\"" + formId + "\";filename=\""+ file.getName() + "\"" + "\r\n" +
                            "Content-Type:application/octet-stream\r\n\r\n";

            outputStream = httpURLConnection.getOutputStream();
            //write header
            outputStream.write(getBytes(header));
            //write file content
            copyFile(file , outputStream);
            //write end boundary  最后数据分隔线
            outputStream.write(getBytes("\r\n--" + BOUNDARY + "--\r\n"));

            outputStream.flush();

            inputStream = httpURLConnection.getInputStream();
            return getData(inputStream, ApiConfig.charset);
        }  catch (Exception e) {
            throw new RuntimeException(e) ;
        } finally {
            closeQuietly(inputStream);
            closeQuietly(outputStream);
            if(httpURLConnection != null)
                httpURLConnection.disconnect();
        }
    }

    public static String post(String requestUrl,String data ,Map<String,String> parameters){
        return sendRequest(requestUrl, HTTP_POST, data);
    }

    public static String get(String requestUrl ,Map<String,String> parameters){
        return sendRequest(requestUrl, HTTP_GET, null);
    }


    /**
     * @param requestUrl
     * @param requestMethod
     * @param data
     * @return
     */
    private static String sendRequest(String requestUrl, String requestMethod, String data) {

        HttpURLConnection httpURLConnection = null ;
        InputStream inputStream  = null ;
        OutputStream outputStream = null ;
        try {

            httpURLConnection = openConnection(requestUrl);

            httpURLConnection.setRequestMethod(requestMethod);

            if (HTTP_GET.equalsIgnoreCase(requestMethod))
                httpURLConnection.connect();

            if(data != null && !data.isEmpty()){
                outputStream = httpURLConnection.getOutputStream();
                outputStream.write(getBytes(data));
                outputStream.flush();
            }

            inputStream = httpURLConnection.getInputStream();
            return getData(inputStream, ApiConfig.charset);
        }  catch (Exception e) {
            throw new RuntimeException(e) ;
        } finally {
            closeQuietly(inputStream);
            closeQuietly(outputStream);
            if(httpURLConnection != null)
                httpURLConnection.disconnect();
        }
    }

    private static HttpURLConnection openConnection(String requestUrl) throws IOException{

        HttpURLConnection httpURLConnection = null ;
        URL url = new URL(requestUrl);
        if(HTTPS_PROTOCAL.equals(url.getProtocol())){
            httpURLConnection = (HttpURLConnection) url.openConnection();
            ((HttpsURLConnection)httpURLConnection).setSSLSocketFactory(sslSocketFactory);
        }

        httpURLConnection.setDoInput(true);
        httpURLConnection.setDoOutput(true);
        httpURLConnection.setUseCaches(false); //不使用缓存

        httpURLConnection.setRequestProperty("Connection", "Keep-Alive");// 设置请求头信息
        httpURLConnection.setRequestProperty("Charset", ApiConfig.charset);

        return httpURLConnection ;
    }


    /**
     * Unconditionally close an <code>InputStream</code>.
     * <p>
     * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored.
     * This is typically used in finally blocks.
     *
     * @param closeable  the InputStream to close, may be null or already closed
     */
    private static void closeQuietly(Closeable closeable) {
        try {
            if (closeable != null) {
                closeable.close();
            }
        } catch (IOException ioe) {
            // ignore
        }
    }

    private static String getData(InputStream input ,String encoding) throws IOException{

        InputStreamReader in = new InputStreamReader(input, encoding);
        StringWriter output = new StringWriter();

        char[] buffer = new char[ApiConfig.DEFAULT_BUFFER_SIZE];
        int n ;
        while (-1 != (n = in.read(buffer))) {
            output.write(buffer, 0, n);
        }
        return output.toString();
    }

    private static void copyFile(File file ,OutputStream outputStream ) throws IOException {

        FileInputStream inputStream = new FileInputStream(file);
        byte[] buf = new byte[1024*4];

        try{
            int n ;
            while((n = inputStream.read(buf) )!= -1) {
                outputStream.write(buf , 0 , n);
            };
        } finally {
            closeQuietly(inputStream);
        }

    }

    private static byte[] getBytes(String data) throws UnsupportedEncodingException{
        return data.getBytes(ApiConfig.charset);
    }

    public static void main(String args[]) throws Exception{
        URL url = new URL("https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1444738730&token=&lang=zh_CN");
        System.out.println(url.getProtocol());
    }

}
